package com.quanz.ckgl.mvc;

import static org.crank.crud.criteria.Comparison.eq;
import static org.crank.crud.criteria.Comparison.like;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.crank.crud.criteria.Criterion;
import org.crank.crud.criteria.Group;
import org.crank.crud.criteria.OrderBy;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.quanz.ckgl.services.Role;
import com.quanz.ckgl.services.User;
import com.quanz.ckgl.services.UserService;
import com.quanz.ckgl.tools.AuthHelper;

/**
 * 用户管理Controlller
 * 
 * @author James Quan
 * @version 2015年10月9日 下午9:20:26
 */
@RestController
public class UserController {

	private UserService userService;

	@Autowired
	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	@RequestMapping("/users_processing.json")
	public DataTablesResponse users_processing(
			@ModelAttribute DataTablesRequest request) {
		DataTablesSearch search = request.getSearch();
		Criterion criterion = null;
		if (search != null && !StringUtils.isEmpty(search.getValue())) {
			String v = "%" + search.getValue() + "%";
			criterion = Group.or(like("account", v), like("name", v));
		}
		int count = userService.findUserCount(criterion);
		DataTablesResponse resp = new DataTablesResponse();
		resp.setDraw(request.getDraw());
		resp.setRecordsFiltered(count);
		resp.setTotalRecords(count);
		if (count > 0) {
			DataTablesOrder[] orders = request.getOrder();
			OrderBy[] orderBy = null;
			if (orders != null && orders.length > 0) {
				DataTablesColumn[] columns = request.getColumns();
				orderBy = new OrderBy[orders.length];
				for (int i = 0; i < orders.length; i++) {
					DataTablesOrder order = orders[i];
					String column = columns[order.getColumn()].getData();
					orderBy[i] = "asc".equals(order.getDir()) ? OrderBy
							.asc(column) : OrderBy.desc(column);
				}
			}
			User[] users = userService.findUser(orderBy, request.getStart(),
					request.getLength(), criterion);
			List<Map<String, Object>> datas = new ArrayList<Map<String, Object>>(
					users.length);
			for (User user : users) {
				Map<String, Object> data = getUserData(user);
				datas.add(data);
			}
			resp.setData(datas.toArray());
		} else {
			resp.setData(new User[0]);
		}
		return resp;
	}

	@RequestMapping("/user/unused")
	public boolean checkAccountUnused(@RequestParam("account") String account) {
		return userService.findUserCount(eq("account", account)) == 0;
	}

	@RequestMapping("/user/{id}")
	public Map<String, Object> getUserById(@PathVariable long id) {
		User user = userService.findUserById(id);
		return getUserData(user);
	}

	@RequestMapping(value = "/user", method = RequestMethod.POST)
	public Map<String, Object> createUser(User user) {
		User newUser = userService.createUser(user);
		return getUserData(newUser);
	}

	@RequestMapping(value = "/user/{id}", method = RequestMethod.PUT)
	public boolean updateUser(@PathVariable long id, @ModelAttribute User user,
			@RequestParam("admin") boolean admin) {
		User u = userService.findUserById(id);
		if (u == null) {
			throw new IllegalArgumentException("user " + id + " not found!");
		}
		u = new User(u);
		u.setName(user.getName());
		u.setStatus(user.getStatus());
		u.setLastModified(DateTime.now());
		userService.updateUser(u);
		int idx = -1;
		Role[] roles = userService.findUserRoles(u);
		for (int i = 0; i < roles.length; i++) {
			Role role = roles[i];
			if ("ADMIN".equals(role.getCode())) {
				idx = i;
				break;
			}
		}
		if (admin) {
			if (idx == -1) {
				roles = ArrayUtils.add(roles,
						userService.findRoleByCode("ADMIN"));
				userService.changeAuthority(user, roles);
			}
		} else {
			if (idx != -1) {
				roles = ArrayUtils.remove(roles, idx);
				userService.changeAuthority(user, roles);
			}
		}
		return true;
	}

	@RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)
	public boolean removeUser(@PathVariable long id) {
		User user = userService.findUserById(id);
		if (user != null) {
			userService.changeAuthority(user, new Role[0]);
			userService.removeUser(user);
			return true;
		} else {
			return false;
		}
	}

	@RequestMapping(value = "/user/reset")
	public boolean resetPassword(@RequestParam("id") long id,
			@RequestParam("pwd") String password) {
		User user = userService.findUserById(id);
		if (user == null) {
			throw new IllegalArgumentException("user " + id + " not found!");
		}
		User u = new User(user);
		u.setPassword(password);
		userService.updateUser(u);
		return true;
	}

	@RequestMapping(value = "/user/changepwd")
	public boolean resetPassword(@RequestParam("oldpwd") String oldPassword,
			@RequestParam("newpwd") String newPassword) {
		String account = AuthHelper.getCurrentUser();
		User user = userService.findUserByAccount(account);
		if (user == null) {
			throw new IllegalArgumentException("user " + account
					+ " not found!");
		}
		String oldPwd = StringUtils.defaultString(user.getPassword());
		String pwd = StringUtils.defaultString(oldPassword);
		if (!StringUtils.equals(oldPwd, pwd)) {
			return false;
		}
		User u = new User(user);
		u.setPassword(newPassword);
		userService.updateUser(u);
		return true;
	}

	protected User getCurrentUser() {
		return userService.findUserByAccount(AuthHelper.getCurrentUser());
	}

	protected Map<String, Object> getUserData(User user) {
		if (user == null) {
			return null;
		}
		boolean admin = false;
		Role[] roles = userService.findUserRoles(user);
		for (Role role : roles) {
			if ("ADMIN".equals(role.getCode())) {
				admin = true;
				break;
			}
		}
		Map<String, Object> data = new HashMap<String, Object>();
		data.put("id", user.getId());
		data.put("account", user.getAccount());
		data.put("name", user.getName());
		data.put("status", user.getStatus());
		data.put("createdTime", user.getCreatedTime());
		data.put("lastModified", user.getLastModified());
		data.put("admin", admin);
		return data;
	}
}
